package com.rem.designPattern.interpreter解释器;

import java.util.Objects;

/**
 * 解释器模式
 * 给定一个语言，定义它的文法的一种表示，并定义一个解释器，这个解释器使用该表示来解释语言中的句子
 * <p>
 * 抽象角色
 *
 * @author Rem
 * @date 2022-11-26
 */
public interface AbstractExpression {

    /**
     * 表达式
     *
     * @param context
     * @return
     */
    int interpret(Context context);
}


/**
 * 终结符表达式角色 变量表达式
 */
class Variable implements AbstractExpression {
    private final String name;

    public Variable(String name) {
        this.name = name;
    }

    @Override
    public int interpret(Context ctx) {
        return ctx.getValue(this);
    }

    @Override
    public String toString() {
        return name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof Variable)) {
            return false;
        }
        Variable variable = (Variable) o;
        return Objects.equals(name, variable.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name);
    }
}

/**
 * 抽象非终结 非终结符表达式角色
 */
abstract class SymbolExpression implements AbstractExpression {
    protected AbstractExpression left;
    protected AbstractExpression right;

    public SymbolExpression(AbstractExpression left, AbstractExpression right) {
        this.left = left;
        this.right = right;
    }
}

/**
 * 非终结符表达式角色 减法表达式
 */
class Minus extends SymbolExpression {

    public Minus(AbstractExpression left, AbstractExpression right) {
        super(left, right);
    }

    @Override
    public int interpret(Context context) {
        return left.interpret(context) - right.interpret(context);
    }

    @Override
    public String toString() {
        return "(" + left.toString() + " - " + right.toString() + ")";
    }
}

/**
 * 非终结符表达式角色  加法表达式
 */
class Plus extends SymbolExpression {

    public Plus(AbstractExpression left, AbstractExpression right) {
        super(left, right);
    }

    @Override
    public int interpret(Context context) {
        return left.interpret(context) + right.interpret(context);
    }

    @Override
    public String toString() {
        return "(" + left.toString() + " + " + right.toString() + ")";
    }
}